/**
 *Copyright (c) 2024 watereyes
 * safetymanagement is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */
package com.koron.hazardsource.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.koron.audit.approval.AfterApprovalService;
import com.koron.audit.domain.Audit;
import com.koron.audit.management.FlowManagement;
import com.koron.common.bean.StaffBean;
import com.koron.common.dfs.FastDFSClientWrapper;
import com.koron.common.generator.DefaultIdGenerator;
import com.koron.hazardsource.domain.*;
import com.koron.hazardsource.mapper.CheckListEntryMapper;
import com.koron.hazardsource.mapper.HazardSourceMapper;
import com.koron.hazardsource.mapper.StandardRiskMapper;
import com.koron.hazardsource.service.api.HazardSourceService;
import com.koron.hazardsource.service.api.IndicationItemsService;
import com.koron.hazardsource.service.api.IndicationTypeService;
import com.koron.hazardsource.util.BusinessCode;
import com.koron.hazardsource.util.Immutable;
import com.koron.hazardsource.util.RiskLECDesc;
import com.koron.hazardsource.util.RiskLevelDesc;
import com.koron.system.domain.DictData;
import com.koron.system.service.api.DictDataService;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.koron.ebs.mybatis.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.swan.bean.MessageBean;

import java.io.InputStream;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
@PropertySource({"classpath:flow.properties"})
public class HazardSourceServiceImpl implements HazardSourceService, AfterApprovalService, InitializingBean {

    private final static  Logger logger = LoggerFactory.getLogger(HazardSourceServiceImpl.class);

    private static Map<RiskLevelDesc, List<Integer>> levelMap = new HashMap<>();

    @Autowired
    private IndicationTypeService indicationTypeService;

    @Autowired
    private IndicationItemsService indicationItemsService;

    @Autowired
    private FastDFSClientWrapper clientWrapper;

    @Autowired
    private DictDataService dataService;

    @Autowired
    private FlowManagement flowManagement;

    @Value("${flow.standard.setCode}")
    private String setCode;
    
    @Value("${safe_standard_hs_add}")
    private String addFlowKey;
    
    @Value("${safe_standard_hs_update}")
    private String updateFlowKey;
    
    @Value("${safe_standard_hs_discard}")
    private String discardFlowKey;

    @Value("${hazard_source_level_key}")
    private String hazardSourceLevelKey;

    @Value("${checklistEntryTypeId}")
    private String checklistEntryTypeId;

    static {
        levelMap.put(RiskLevelDesc.Minor, Arrays.asList(1, 2, 3, 4));
        levelMap.put(RiskLevelDesc.Ordinary, Arrays.asList(5, 6, 8, 9));
        levelMap.put(RiskLevelDesc.Serious, Arrays.asList(10, 12, 15, 16));
        levelMap.put(RiskLevelDesc.Important, Arrays.asList(20, 25));
    }


    @SuppressWarnings({"unchecked", "rawtypes"})
    @Override
    public void afterPropertiesSet() throws Exception {
        Map map = flowManagement.getHandlers();
        map.put(HazardSource.class.getName(), this);
    }



    @Override
	public void processDiscard(Audit audit) {
		// TODO Auto-generated method stub

	}



	@SuppressWarnings("deprecation")
    @Override
    public void editApproval(Audit audit) {
        List<String> idList = JSONObject.parseArray(audit.getBusinessIds(), String.class);
        try (SessionFactory factory = new SessionFactory();) {
            HazardSourceMapper sourceMapper = factory.getMapper(HazardSourceMapper.class);
            StandardRiskMapper riskMapper = factory.getMapper(StandardRiskMapper.class);
            List<HazardSource> list = sourceMapper.queryByIdList("hazard_source_history", idList);
            for (HazardSource hazardSource : list) {
                hazardSource.setState(1);
                hazardSource.setFstatusflag(2);
                List<StandardRisk> tempList = riskMapper.queryByHazrdSourceId("tbl_risk_history", hazardSource.getId(), null, null);
                hazardSource.setRisks(tempList);
            }
            //保存危险源
            saveSourceAndRisk(list);
            updateFstatusflag(idList, 2);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
        }
    }

    @SuppressWarnings({"deprecation"})
    @Override
    public void discardApproval(Audit audit) {
        List<String> codeList = null;
        try (SessionFactory factory = new SessionFactory();) {
            List<String> idList = JSONObject.parseArray(audit.getBusinessIds(), String.class);
            HazardSourceMapper mapper = factory.getMapper(HazardSourceMapper.class);
            List<HazardSource> list = mapper.queryByIdList("hazard_source_history", idList);
            codeList = list.stream().map(HazardSource::getCode).collect(Collectors.toList());
        }
        if (Objects.nonNull(codeList) && !codeList.isEmpty()) {
            updateState(codeList, 0);
        }
    }



    @SuppressWarnings("deprecation")
    @Override
    public List<HazardSource> queryByCondition(String table, String name, String indicationLevelId, Integer riskLevelStart,Integer riskLevelEnd,String businessTypeId, String hazardTypeId, Boolean fitAllBusiness, Integer state, Integer start, Integer rows) {
        try (SessionFactory factory = new SessionFactory()) {
        	if(name != null){
            	name = "%" + name + "%";
            }
            HazardSourceMapper sourceMapper = factory.getMapper(HazardSourceMapper.class);
            StandardRiskMapper srMapper = factory.getMapper(StandardRiskMapper.class);
            List<HazardSource> list = sourceMapper.selectByCondition(table, name, indicationLevelId, riskLevelStart,riskLevelEnd, businessTypeId, hazardTypeId, fitAllBusiness, state, start, rows);
            for (HazardSource hs : list) {
                setProperties(hs, srMapper, "tbl_risk");
			}
            return list;
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            logger.error(e.getMessage(),e);
            return null;
        }
    }


    private void setProperties(HazardSource source, StandardRiskMapper standardRiskMapper, String tableName) {
        Map<String, DictData> cacheMap = dataService.getCacheMap();
        Map<String, IndicationItems> cache = indicationItemsService.getCacheMap();
        //set property of hazard source
        if (StringUtils.isNotBlank(source.getBusinessTypeId())) {
            DictData business = cacheMap.get(source.getBusinessTypeId());
            source.setBusinessTypeName(business != null? business.getDictLabel() : "");
        }
        if (StringUtils.isNotBlank(source.getHazardTypeId())) {
            DictData hazard = cacheMap.get(source.getHazardTypeId());
            source.setHazardTypeName(hazard != null? hazard.getDictLabel() : "");
        }
        if (StringUtils.isNotBlank(source.getIndicationLevelId())) {
            IndicationItems indicationItems = cache.get(source.getIndicationLevelId());
            source.setIndicationLevelName(indicationItems != null? indicationItems.getName() : "");
        }
        //query risks
        List<StandardRisk> risks = standardRiskMapper.queryByHazrdSourceId(tableName, source.getId(), null, null);
        if (risks != null && !risks.isEmpty()) {
            risks.stream().forEach(risk -> {
                if (StringUtils.isNotBlank(risk.getAccidentTypeId())) {
                    DictData dictData = cacheMap.get(risk.getAccidentTypeId());
                    risk.setAccidentTypeName(dictData != null? dictData.getDictLabel() : "");
                }
                if ("LS".equals(source.getIdentificationType())){
                    RiskLevelDesc levelDesc = match(risk.getRiskLevel());
                    risk.setRiskLevelName(levelDesc != null? levelDesc.getName() : "");
                    levelDesc = match(risk.getResidueLevel());
                    risk.setResidueLevelName(levelDesc != null? levelDesc.getName() : "");
                }else{
                    RiskLECDesc lecDesc=matchRiskLECDesc( new BigDecimal(risk.getRiskLevel()));
                    risk.setRiskLevelName(lecDesc != null? lecDesc.getName() : "");
                }
            });
        }

        setHazardSourceLevel(source, risks);
        source.setRisks(risks);
    }


    private void setHazardSourceLevel(HazardSource source, List<StandardRisk> risks) {
        if (risks != null && !risks.isEmpty()) {
            risks = risks.stream().filter(risk -> risk.getRiskLevel() != null).collect(Collectors.toList());
            if (!risks.isEmpty()) {
                StandardRisk standardRisk = risks.stream().max(Comparator.comparing(StandardRisk::getRiskLevel)).get();
                source.setRiskLevel(standardRisk.getRiskLevel());
                source.setRiskLevelName(standardRisk.getRiskLevelName());
            }
        }
    }

    @SuppressWarnings("deprecation")
    @Override
    public Integer countByCondition(String table, String name, String indicationLevelId, Integer riskLevelStart,Integer riskLevelEnd, String businessTypeId, String hazardTypeId, Boolean fitAllBusiness, Integer state) {
        try (SessionFactory factory = new SessionFactory()) {
            HazardSourceMapper sourceMapper = factory.getMapper(HazardSourceMapper.class);
            if(name != null){
            	name = "%" + name + "%";
            }
            Integer totalNumber = sourceMapper.countByCondition(table, name, indicationLevelId, riskLevelStart,riskLevelEnd, businessTypeId, hazardTypeId, fitAllBusiness, state);
            return totalNumber;
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            logger.error(e.getMessage(),e);
            return 0;
        }
    }

    @SuppressWarnings("deprecation")
    @Override
    public HazardSource queryOneById(String table, String id) {
        try (SessionFactory factory = new SessionFactory()) {
            HazardSourceMapper sourceMapper = factory.getMapper(HazardSourceMapper.class);
            HazardSource source = sourceMapper.queryOneById(table, id);
            if (source == null) {
                return null;
            }
            StandardRiskMapper riskMapper = factory.getMapper(StandardRiskMapper.class);
            setProperties(source, riskMapper, "tbl_risk");
            return source;
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            logger.error(e.getMessage(),e);
            return null;
        }
    }

    @SuppressWarnings({"deprecation", "rawtypes"})
    @Override
    public MessageBean<?> getHistoryList(String code) {
        MessageBean<List> msg = MessageBean.create(0, "success", List.class);
        try (SessionFactory factory = new SessionFactory()) {
            HazardSourceMapper sourceMapper = factory.getMapper(HazardSourceMapper.class);
            StandardRiskMapper srMapper = factory.getMapper(StandardRiskMapper.class);
            List<HazardSource> list = sourceMapper.queryHstory(code);
            for (HazardSource hazardSource : list) {
                setProperties(hazardSource, srMapper, "tbl_risk_history");
            }
            msg.setData(list);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            msg.setCode(BusinessCode.MESSAGE_CODE_EXCEPTION);
            msg.setDescription(BusinessCode.MESSAGE_DESCRIPTION_EXCEPTION);
            return msg;
        }
        return msg;
    }

    @SuppressWarnings({"resource", "unused"})
    @Override
    public MessageBean<?> importFromExcel(StaffBean user, MultipartFile file, String title, String note) throws Exception {
        Map<HazardSource, List<StandardRisk>> map = new HashMap<>();
        MessageBean<?> msg = new MessageBean<>();
        //先将文件上传到文件服务器
        if (null == file) {
            msg.setCode(22001);
            msg.setDescription("上传文件为空");
            return msg;
        }
        String fileName = file.getOriginalFilename();
        String filePath = clientWrapper.uploadFile(file) + "#" + fileName;//文件上传的路径

        //处理excel中的内容
        InputStream inputStream = file.getInputStream();

        new Thread(){
            @Override
            public void run(){
            	try {
            		XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
                    if (null == workbook) {
                    	logger.error("上传文件为空");
                        return;
                    }
                    XSSFSheet sheet = workbook.getSheetAt(0);
                    if(sheet == null){
                    	logger.error("上传文件为空");
                        return;
                    }
                    List<CellRangeAddress> combineCell = getCombineCell(sheet);
                    int rowsNumm = sheet.getPhysicalNumberOfRows();
                    for (int i = 4; i < rowsNumm; ) {
                        XSSFRow row = sheet.getRow(i);
                        // 合并了多行，取合并后单元格范围信息
                        CellRangeAddress cellRange = getCellRange(combineCell, row.getCell(1));
                        int lastRow = i;
                        if (cellRange != null) {
                            lastRow = cellRange.getLastRow();
                        }
                        List<XSSFRow> rows = new ArrayList<>();
                        while (lastRow >= i) {
                            rows.add(sheet.getRow(i));
                            i++;
                        }
                        parseRows(rows, map, user);
                    }
                    distinguishAndPersistence(filePath, user, map, title, note);
				} catch (Exception e) {
					logger.error(e.getMessage(),e);
				}
            }
        }.start();

        msg.setCode(0);
        msg.setDescription("数据解析中,稍后请在任务管理中查看导入结果。");
        return msg;
    }


    @SuppressWarnings({"rawtypes", "unchecked"})
    private Map addCheck(List<HazardSource> hsList) {
        Map map = new HashMap();
        for (HazardSource source : hsList) {
            if (null == source) {
                map.put("code", 22001);
                map.put("description", "未填写危险源信息无法保存");
                return map;
            }
            List<StandardRisk> riskList = source.getRisks();
            if (null == riskList) {
                map.put("code", 22001);
                map.put("description", "未填写危险源的风险项信息无法保存");
                return map;
            }
            //校验危险源的字段
            if (StringUtils.isEmpty(source.getName())) {
                map.put("code", 22001);
                map.put("description", "危险源名称不能为空");
                return map;
            }
            if (null == source.getFitAllBusiness()) {
                map.put("code", 22001);
                map.put("description", "危险源是否通用必须选择");
                return map;
            }
            if (!source.getFitAllBusiness()) {
                if (StringUtils.isEmpty(source.getBusinessTypeId())) {
                    map.put("code", 22001);
                    map.put("description", "非通用，危险源业态不能为空");
                    return map;
                }
            }
            if (StringUtils.isEmpty(source.getHazardTypeId())) {
                map.put("code", 22001);
                map.put("description", "危险源类型不能为空");
                return map;
            }
            if (StringUtils.isEmpty(source.getIndicationLevelId())) {
                map.put("code", 22001);
                map.put("description", "危险源等级不能为空");
                return map;
            }
            if(StringUtils.isEmpty(source.getIdentificationType())){
                map.put("code", 22001);
                map.put("description", "危险源辨识方式不能为空");
                return map;
            }
            if(!"LS".equals(source.getIdentificationType())&&!"LEC".equals(source.getIdentificationType())){
                map.put("code", 22001);
                map.put("description", "危险源辨识方式值不合理，辨识方式为“LS”或者“LEC”");
                return map;
            }
            int riskLevel = 0;
            //校验风险的字段
            for (StandardRisk risk : riskList) {
                if (StringUtils.isEmpty(risk.getRiskInfo())) {
                    map.put("code", 22001);
                    map.put("description", "风险列表中存在风险描述为空");
                    return map;
                }
                if (StringUtils.isEmpty(risk.getAccidentTypeId())) {
                    map.put("code", 22001);
                    map.put("description", "风险列表中存在风险事故类型为空");
                    return map;
                }
                if (StringUtils.isEmpty(risk.getRiskReason())) {
                    map.put("code", 22001);
                    map.put("description", "风险列表中存在风险原因描述为空");
                    return map;
                }
                if("LS".equals(source.getIdentificationType())){
                    if (null == risk.getPossibility()) {
                        map.put("code", 22001);
                        map.put("description", "风险列表中存在风险可能性为空");
                        return map;
                    }
                    if (null == risk.getSeverity()) {
                        map.put("code", 22001);
                        map.put("description", "风险列表中存在风险项严重性为空");
                        return map;
                    }

                    //计算风险等级
                    risk.setRiskLevel(risk.getPossibility() * risk.getSeverity());
                    if(riskLevel < risk.getRiskLevel()){
                        riskLevel = risk.getRiskLevel();
                    }
                    RiskLevelDesc levelDesc = match(risk.getRiskLevel());
                    risk.setControlLevel(levelDesc != null? levelDesc.getControlDesc() : "");
                    if (StringUtils.isBlank(risk.getControlLevel())) {
                        map.put("code", 22001);
                        map.put("description", "风险列表中存在风险管控层级为空");
                        return map;
                    }
                    if (null == risk.getRiskLevel()) {
                        map.put("code", 22001);
                        map.put("description", "风险列表中存在风险项等级为空");
                        return map;
                    }
                    if(risk.getResiduePossibility() != null && risk.getResidueSeverity() !=null){
                        //计算残余风险等级
                        risk.setResidueLevel(risk.getResiduePossibility() * risk.getResidueSeverity());
                        levelDesc = match(risk.getResidueLevel());
                        risk.setResidueControlLevel(levelDesc != null? levelDesc.getControlDesc() : "");
                    }
                }else {
                    //LEC辨识方式校验和计算危险源等级
                    if (null==risk.getOccurencePossibility()){
                        map.put("code", 32002);
                        map.put("description", "风险列表中发生事故可能性为空");
                        return map;
                    }
                    BigDecimal temp=risk.getOccurencePossibility().multiply(risk.getFrequently());
                    BigDecimal result=temp.multiply(risk.getConsequence());
                    risk.setRiskLevel(result.intValue());
                    if(riskLevel < risk.getRiskLevel()){
                        riskLevel = risk.getRiskLevel();
                    }
                    RiskLECDesc riskLECDesc = matchRiskLECDesc(result);
                    risk.setControlLevel(riskLECDesc != null? riskLECDesc.getControlDesc() : "");
                }
                source.setRiskLevel(riskLevel);
                }
        }
        map.put("code", 0);
        map.put("description", "校验成功");
        return map;
    }

    private String generateCode(SessionFactory factory, HazardSource source) {
        HazardSourceMapper mapper = factory.getMapper(HazardSourceMapper.class);
        Boolean all = source.getFitAllBusiness();
        Integer count = 0;
        String businessValue = "";
        String hazardValue = "";
        String fitAllBusiness = "";
        if (all) {
            count = mapper.countByCondition("hazard_source", null, null,null,null, null, null, all, null);
            fitAllBusiness = "C";
        } else {
            DictData businessType = dataService.queryOne(source.getBusinessTypeId()).getData();
            if (businessType != null) {
                businessValue = businessType.getDictValue();
            }else{
            	businessValue="#";
            }
            DictData hazardType = dataService.queryOne(source.getHazardTypeId()).getData();
            if (hazardType != null) {
                hazardValue = hazardType.getDictValue();
            }else{
            	hazardValue = "#";
            }
            count = mapper.countByCondition("hazard_source", null, null,null,null, source.getBusinessTypeId(), source.getHazardTypeId(), null, null);
        }
        count++;
        NumberFormat nf = NumberFormat.getInstance();
        nf.setGroupingUsed(false);
        nf.setMaximumIntegerDigits(3); // 设置最大整数位数
        nf.setMinimumIntegerDigits(3); // 设置最小整数位数
        StringBuilder sb = new StringBuilder();
        sb.append("W").append(businessValue).append(hazardValue).append(fitAllBusiness).append(nf.format(count));
        return sb.toString();
    }


    @SuppressWarnings({"deprecation"})
    @Override
    public List<String> saveSourceAndRisk(List<HazardSource> hsList) {
        SessionFactory factory = new SessionFactory();
        List<String> list = new ArrayList<String>();
        try {
            HazardSourceMapper sourceMapper = factory.getMapper(HazardSourceMapper.class);
            StandardRiskMapper riskMapper = factory.getMapper(StandardRiskMapper.class);
            CheckListEntryMapper checkListMapper = factory.getMapper(CheckListEntryMapper.class);
            for (HazardSource source : hsList) {
            	String historyId = source.getId();  //历史版本id
                source.setState(1); //发布状态
                List<StandardRisk> riskList = source.getRisks();
                //校验通过，开始保存，先判断是新增操作还是修改操作
                if (StringUtils.isEmpty(source.getCode())) {
                    //新增操作
                    String hazardSourceId = DefaultIdGenerator.getInstance().generateLongId();
                    Date date = new Date();
                    source.setId(hazardSourceId);
                    source.setCode(generateCode(factory, source));
                    source.setAddTime(date);
                    source.setUpdateTime(date);
                    for (StandardRisk risk : riskList) {
                        risk.setId(DefaultIdGenerator.getInstance().generateLongId());
                        risk.setAddTime(date);
                        risk.setHazardSourceId(hazardSourceId);
                    }
                    sourceMapper.insert("hazard_source", source);
                    riskMapper.batchInsert("tbl_risk", riskList);
                    sourceMapper.updateCode(historyId, source.getCode());
                } else {
                    Date date = new Date();
                    HazardSource sourceOld = sourceMapper.queryOneByCode("hazard_source", source.getCode());
                    if (sourceOld == null) {
                        //新增操作
                        source.setId(DefaultIdGenerator.getInstance().generateLongId());
                        source.setCode(generateCode(factory, source));
                        source.setAddTime(date);
                        for (StandardRisk risk : riskList) {
                            risk.setId(DefaultIdGenerator.getInstance().generateLongId());
                            risk.setUpdateTime(date);
                            risk.setAddTime(date);
                            risk.setHazardSourceId(source.getId());
                        }
                        sourceMapper.insert("hazard_source", source);
                        riskMapper.batchInsert("tbl_risk", riskList);
                        sourceMapper.updateCode(historyId, source.getCode());
                    } else {
                        //修改操作
                        //先删除之前的填写的风险项
                        riskMapper.deleteByHazardSourceId("tbl_risk", sourceOld.getId());
                        source.setId(sourceOld.getId());
                        source.setUpdateTime(date);
                        for (StandardRisk risk : riskList) {
                            risk.setId(DefaultIdGenerator.getInstance().generateLongId());
                            risk.setUpdateTime(date);
                            risk.setAddTime(date);
                            risk.setHazardSourceId(source.getId());
                        }
                        sourceMapper.update("hazard_source", source);
                        riskMapper.batchInsert("tbl_risk", riskList);
                    }
                }

                list.add(source.getId());
                //检查表
                CheckListEntry checkList = checkListMapper.queryByCode("checklist_entry", source.getCode());
                if (checkList == null) {
                    checkList = new CheckListEntry();
                    checkList.setAddTime(source.getAddTime());
                    checkList.setAddUser(source.getAddUser());
                    checkList.setAddUserName(source.getAddUserName());
                    checkList.setUpdateTime(checkList.getAddTime());
                    checkList.setUpdateUser(checkList.getAddUser());
                    checkList.setUpdateUserName(checkList.getUpdateUserName());
                    checkList.setBusinessTypeId(source.getBusinessTypeId());
                    checkList.setCode(source.getCode());
                    checkList.setHazardSourceId(source.getHazardTypeId());
                    checkList.setId(DefaultIdGenerator.getInstance().generateLongId());
                    checkList.setChecklistEntryTypeId(checklistEntryTypeId);
                    checkList.setHasItems(0);
                    checkList.setState(1);
                    checkList.setName(source.getName() + "检查表");
                    checkList.setFstatusflag(1);
                    //新增检查表
                    checkListMapper.insert("checklist_entry", checkList);
                }
            }
            factory.close();
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            if (null != factory)
                factory.close(false);
            logger.error(e.getMessage(),e);
        }finally {
            if (null != factory){
                factory.close();
            }
        }
        return list;
    }

    @SuppressWarnings({"resource", "rawtypes", "deprecation"})
    @Override
    public MessageBean<List> saveSourceAndRiskDraft(List<HazardSource> hsList, StaffBean user) {
        MessageBean<List> msg = new MessageBean<>();
        SessionFactory factory = new SessionFactory();
        try {
            //新增校验
            Map checkMap = addCheck(hsList);
            int code = (int) checkMap.get("code");
            String description = (String) checkMap.get("description");
            if (code != 0) {
                msg.setCode(code);
                msg.setDescription(description);
                return msg;
            }
            List<String> idList = new ArrayList<>();

            HazardSourceMapper sourceMapper = factory.getMapper(HazardSourceMapper.class);
            StandardRiskMapper riskMapper = factory.getMapper(StandardRiskMapper.class);
            for (HazardSource source : hsList) {
                List<StandardRisk> riskList = source.getRisks();
                if(source.getState() == null){
                	source.setState(1);
                }
                if(source.getFitAllBusiness()){
                	source.setBusinessTypeId(null);
                }
                source.setAddTime(new Date());
                source.setAddUser(user.getCode());
                source.setAddUserName(user.getName());
                source.setUpdateTime(new Date());
                source.setUpdateUser(user.getCode());
                source.setUpdateUserName(user.getName());
                source.setFstatusflag(0); //待提交状态
                source.setDerivation(source.getDerivation() == null ? 1:source.getDerivation());
                for (StandardRisk risk : riskList) {
                    if (risk.getRiskLevel() == null && risk.getSeverity() != null && risk.getPossibility() != null) {
                        risk.setRiskLevel(risk.getSeverity() * risk.getPossibility());
                    }
                    if (risk.getResidueLevel() == null && risk.getResidueSeverity() != null && risk.getResiduePossibility() != null) {
                        risk.setResidueLevel(risk.getResidueSeverity() * risk.getResiduePossibility());
                    }
                }
                //校验通过，开始保存，先判断是新增操作还是修改操作
                if (StringUtils.isEmpty(source.getId())) {
                    //新增操作
                    String hazardSourceId = DefaultIdGenerator.getInstance().generateLongId();
                    source.setId(hazardSourceId);
                    for (StandardRisk risk : riskList) {
                        risk.setId(DefaultIdGenerator.getInstance().generateLongId());
                        risk.setHazardSourceId(hazardSourceId);
                    }
                    sourceMapper.insert("hazard_source_history", source);
                    riskMapper.batchInsert("tbl_risk_history", riskList);
                } else {
                    //修改操作
                    //先删除之前的填写的风险项
                    riskMapper.deleteByHazardSourceId("tbl_risk_history", source.getId());
                    for (StandardRisk risk : riskList) {
                        risk.setHazardSourceId(source.getId());
                        risk.setId(DefaultIdGenerator.getInstance().generateLongId());
                    }
                    sourceMapper.update("hazard_source_history", source);
                    riskMapper.batchInsert("tbl_risk_history", riskList);
                }
                idList.add(source.getId());
            }
            factory.close();
            msg.setCode(0);
            msg.setDescription("保存成功");
            msg.setData(idList);
            return msg;
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            if (null != factory)
                factory.close(false);
            logger.error(e.getMessage(),e);
            msg.setCode(BusinessCode.MESSAGE_CODE_EXCEPTION);
            msg.setDescription(BusinessCode.MESSAGE_DESCRIPTION_EXCEPTION);
            return msg;
        }finally {
            if (null != factory){
                factory.close();
            }
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public MessageBean<?> submitSourceAndRisk(List<HazardSource> hsList, StaffBean user, String title, String note) {
        MessageBean<?> msg = saveSourceAndRiskDraft(hsList, user);
        try {
            List<String> idList = new ArrayList<String>();
            if (msg.getData() != null) {
                idList = (List<String>) msg.getData();
            } else {
                return msg;
            }
            //启动流程
            Audit audit = new Audit(title, note, user.getName(), new Date());
            audit.setId(DefaultIdGenerator.getInstance().generateLongId());
            audit.setTitle(title);
            audit.setDescription(note);
            audit.setInitiatorCode(user.getCode());
            audit.setTarget(HazardSource.class.getName());
            audit.setSetCode(setCode);
            audit.setTemplateKey(addFlowKey);
            audit.setOperation(1);
            audit.setState(1);
            audit.setFlowType(1);
            audit.setFlowName(Immutable.ADD_STD_HAZARD_SOURCE);
            audit.setBusinessIds(new Gson().toJson(idList));
            if (!flowManagement.initFlow(user, audit, new HashMap<>())) {
            	delete(idList);
                msg.setCode(BusinessCode.MESSAGE_CODE_FLOW_EXCEPTION);
                msg.setDescription(BusinessCode.MESSAGE_DESCRIPTION_FLOW_EXCEPTION);
                return msg;
            }
            updateFstatusflag(idList, 1);  //审批中
            msg.setDescription("提交成功");
            return msg;
        } catch (Exception e) {
            return msg;
        }
    }

    @SuppressWarnings("deprecation")
	public void delete(List<String> idList){
    	try (SessionFactory factory = new SessionFactory();) {
            HazardSourceMapper sourceMapper = factory.getMapper(HazardSourceMapper.class);
            StandardRiskMapper srMapper = factory.getMapper(StandardRiskMapper.class);
            sourceMapper.batchDelete("hazard_source_history", idList);
            for (String str : idList) {
            	srMapper.deleteByHazardSourceId("tbl_risk_history", str);
			}
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
        }
    }

    /**
     * 修改危险源状态
     *
     * @param codeList
     * @param state
     */
    @SuppressWarnings("deprecation")
    public void updateState(List<String> codeList, int state) {
        try (SessionFactory factory = new SessionFactory();) {
            HazardSourceMapper sourceMapper = factory.getMapper(HazardSourceMapper.class);
            sourceMapper.updateState(codeList, state);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
        }
    }

    /**
     * 修改危险源审批状态
     *
     * @param idList
     * @param fstatusflag
     */
    @SuppressWarnings("deprecation")
    public void updateFstatusflag(List<String> idList, int fstatusflag) {
        try (SessionFactory factory = new SessionFactory();) {
            HazardSourceMapper sourceMapper = factory.getMapper(HazardSourceMapper.class);
            sourceMapper.updateFstatusflag(idList, fstatusflag);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
        }
    }

    @SuppressWarnings("deprecation")
    @Override
    public MessageBean<Boolean> discard(List<String> idList, StaffBean user, String title, String note) {
        MessageBean<Boolean> msg = MessageBean.create(BusinessCode.MESSAGE_CODE_SUCCESS, BusinessCode.MESSAGE_DESCRIPTION_SUCCESS, boolean.class);
        SessionFactory factory = new SessionFactory();
        try {
            HazardSourceMapper sourceMapper = factory.getMapper(HazardSourceMapper.class);
            StandardRiskMapper riskMapper = factory.getMapper(StandardRiskMapper.class);
            List<HazardSource> list = sourceMapper.queryByIdList("hazard_source", idList);
            List<StandardRisk> riskList = new ArrayList<StandardRisk>();
            List<String> newIdList = new ArrayList<String>();
            for (HazardSource hazardSource : list) {
                String id = DefaultIdGenerator.getInstance().generateLongId();
                List<StandardRisk> tempList = riskMapper.queryByHazrdSourceId("tbl_risk", hazardSource.getId(), null, null);
                for (StandardRisk temp : tempList) {
                    temp.setId(DefaultIdGenerator.getInstance().generateLongId());
                    temp.setHazardSourceId(id);
                }
                hazardSource.setState(0);
                hazardSource.setId(id);
                hazardSource.setFstatusflag(0);
                riskList.addAll(tempList);
                newIdList.add(id);
            }
            if (list.isEmpty()) {
                msg.setCode(BusinessCode.MESSAGE_CODE_SERVICE_EXCEPTION);
                msg.setDescription(BusinessCode.MESSAGE_DESCRIPTION_SERVICE_EXCEPTION);
                factory.close(false);
                return msg;
            }
            sourceMapper.batchInsertHazard("hazard_source_history", list);
            riskMapper.batchInsert("tbl_risk_history", riskList);
            //启动流程
            Audit audit = new Audit(title, note, user.getName(), new Date());
            audit.setId(DefaultIdGenerator.getInstance().generateLongId());
            audit.setTitle(title);
            audit.setDescription(note);
            audit.setInitiatorCode(user.getCode());
            audit.setTarget(HazardSource.class.getName());
            audit.setSetCode(setCode);
            audit.setTemplateKey(discardFlowKey);
            audit.setOperation(2);
            audit.setState(1);
            audit.setFlowType(1);
            audit.setFlowName(Immutable.DISCARD_STD_HAZARD_SOURCE);
            audit.setBusinessIds(new Gson().toJson(newIdList));
            if (!flowManagement.initFlow(user, audit, new HashMap<>())) {
                factory.close(false);
                msg.setCode(BusinessCode.MESSAGE_CODE_FLOW_EXCEPTION);
                msg.setDescription(BusinessCode.MESSAGE_DESCRIPTION_FLOW_EXCEPTION);
            }
            factory.close();
            return msg;
        } catch (Exception e) {
            msg.setCode(BusinessCode.MESSAGE_CODE_EXCEPTION);
            msg.setDescription(BusinessCode.MESSAGE_DESCRIPTION_EXCEPTION);
            factory.close(false);
            return msg;
        }finally {
            if (null != factory){
                factory.close();
            }
        }
    }


    @SuppressWarnings({ "deprecation", "rawtypes" })
	@Override
	public MessageBean<?> getProcessData(String ids) {
    	MessageBean<List> msg = MessageBean.create(0, "success", List.class);
        try (SessionFactory factory = new SessionFactory();) {
        	List<String> idList = JSONObject.parseArray(ids, String.class);
            HazardSourceMapper sourceMapper = factory.getMapper(HazardSourceMapper.class);
            StandardRiskMapper riskMapper = factory.getMapper(StandardRiskMapper.class);
            List<HazardSource> list = sourceMapper.queryByIdList("hazard_source_history", idList);
            for (HazardSource hazardSource : list) {
                setProperties(hazardSource, riskMapper, "tbl_risk_history");
            }
            msg.setData(list);
        } catch (Exception e) {
        	msg.setCode(BusinessCode.MESSAGE_CODE_EXCEPTION);
            msg.setDescription(BusinessCode.MESSAGE_DESCRIPTION_EXCEPTION);
            return msg;
        }
        return msg;
	}

	@SuppressWarnings({"rawtypes", "deprecation"})
    @Override
    public MessageBean<?> getDraftList(StaffBean user) {
        MessageBean<List> msg = MessageBean.create(BusinessCode.MESSAGE_CODE_SUCCESS, BusinessCode.MESSAGE_DESCRIPTION_SUCCESS, List.class);
        try (SessionFactory factory = new SessionFactory();) {
            HazardSourceMapper sourceMapper = factory.getMapper(HazardSourceMapper.class);
            StandardRiskMapper riskMapper = factory.getMapper(StandardRiskMapper.class);
            List<HazardSource> hsList = sourceMapper.getDraftList(user.getCode());
            for (HazardSource hs : hsList) {
                setProperties(hs, riskMapper, "tbl_risk_history");
            }
            msg.setData(hsList);
        } catch (Exception e) {
            msg.setCode(BusinessCode.MESSAGE_CODE_EXCEPTION);
            msg.setDescription(BusinessCode.MESSAGE_DESCRIPTION_EXCEPTION);
        }
        return msg;
    }

    @SuppressWarnings("deprecation")
	@Override
	public MessageBean<?> deleteDraft(String id) {
    	MessageBean<?> msg = MessageBean.create(BusinessCode.MESSAGE_CODE_SUCCESS, BusinessCode.MESSAGE_DESCRIPTION_SUCCESS, void.class);
    	SessionFactory factory = new SessionFactory();
        try{
            HazardSourceMapper sourceMapper = factory.getMapper(HazardSourceMapper.class);
            StandardRiskMapper riskMapper = factory.getMapper(StandardRiskMapper.class);
            sourceMapper.deleteDraft(id);
            riskMapper.deleteDraft(id);
            factory.close();
        } catch (Exception e) {
        	factory.close(false);
            msg.setCode(BusinessCode.MESSAGE_CODE_EXCEPTION);
            msg.setDescription(BusinessCode.MESSAGE_DESCRIPTION_EXCEPTION);
        }
        return msg;
	}


	//具体业务基本都在此方法执行
    @SuppressWarnings("unchecked")
	private void distinguishAndPersistence(String filePath, StaffBean user,
    		Map<HazardSource, List<StandardRisk>> map,String title, String note) {
    	MessageBean<?> msg = new MessageBean<>();
        List<HazardSource> beanList = new ArrayList<>();
        //到目前为止危险源和风险等数据都是excel表中原始数据，没有添加其他属性，下面的处理中将会添加
        for (Map.Entry<HazardSource, List<StandardRisk>> entry : map.entrySet()) {
            HazardSource hazard = entry.getKey();
            if(hazard == null){
            	continue;
            }
            List<StandardRisk> riskList = entry.getValue();
            if(riskList.isEmpty()){
            	continue;
            }
            hazard.setRisks(riskList);
            beanList.add(hazard);
        }
        try {
        	msg = saveSourceAndRiskDraft(beanList, user);
            List<String> idList = new ArrayList<String>();
            if (msg.getData() != null) {
                idList = (List<String>) msg.getData();
            } else {
                return;
            }
            Audit audit = new Audit(title, note, user.getName(), new Date());
            audit.setId(DefaultIdGenerator.getInstance().generateLongId());
            audit.setTitle(title);
            audit.setDescription(note);
            audit.setInitiatorCode(user.getCode());
            audit.setTarget(HazardSource.class.getName());
            audit.setSetCode(setCode);
            audit.setTemplateKey(addFlowKey);
            audit.setOperation(1);
            audit.setState(1);
            audit.setFlowType(1);
            audit.setFlowName(Immutable.ADD_STD_HAZARD_SOURCE);
            audit.setBusinessIds(new Gson().toJson(idList));
            audit.setAttachment(filePath);
            if (!flowManagement.initFlow(user, audit, new HashMap<>())) {
            	//流程启动失败,删除草稿
            	delete(idList);
                //数据导入失败，将上传的文件删除
                clientWrapper.deleteFile(filePath.split("#")[0]);
                logger.error("数据已保存，流程启动失败");
                return;
            }
            updateFstatusflag(idList, 1);  //审批中
            msg.setDescription("提交成功");
            return;
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            if (StringUtils.isNotBlank(filePath)) {
                clientWrapper.deleteFile(filePath.split("#")[0]);
            }
            return;
        }
    }

    // 单个危险源和多个风险
    private void parseRows(List<XSSFRow> rows, Map<HazardSource, List<StandardRisk>> map, StaffBean user) {
        HazardSource hazardSource = null;
        List<StandardRisk> riskList = new ArrayList<>();
        for (int i = 0; i < rows.size(); i++) {
            if (i == 0) {
                hazardSource = parseHazardSource(rows.get(i), user);
                if (hazardSource == null) {
                    return;
                }
            }
            StandardRisk risk = parseRisk(rows.get(i), user,hazardSource.getIdentificationType());
            if (risk != null) {
                riskList.add(risk);
            }
        }
        map.put(hazardSource, riskList);
    }

    private HazardSource parseHazardSource(XSSFRow row, StaffBean user) {
        HazardSource hazard = new HazardSource(user.getCode(), user.getName());
        hazard.setFitAllBusiness(true);
        String sourceName = getCellValue(row.getCell(1));
        String fitAll = getCellValue(row.getCell(2));
        if (StringUtils.isBlank(fitAll)) {
            fitAll = "n";
        }

        if (fitAll.equalsIgnoreCase("否") || fitAll.equalsIgnoreCase("n") || fitAll.equalsIgnoreCase("no")) {
            hazard.setFitAllBusiness(false);
            String businessTypeName = getCellValue(row.getCell(3));
            if (StringUtils.isBlank(businessTypeName)) {
                return null;
            }
            DictData businessTypeItem = dataService.matchDictData("业态", businessTypeName);
            if (businessTypeItem == null) {
                return null;
            }
            hazard.setBusinessTypeId(businessTypeItem.getId());
            hazard.setBusinessTypeName(businessTypeName);
        }

        String hazardTypeName = getCellValue(row.getCell(4));
        if (StringUtils.isBlank(sourceName) || StringUtils.isBlank(hazardTypeName)) {
            return null;
        }

        DictData hazardTypeItem = dataService.matchDictData("危险源类型", hazardTypeName);
        if (hazardTypeItem == null) {
            return null;
        }

        IndicationType indicationType = indicationTypeService.fetchForKey(hazardSourceLevelKey);
        String indicationLevelName = getCellValue(row.getCell(5));
        if (StringUtils.isBlank(indicationLevelName) || StringUtils.isBlank(indicationLevelName)) {
            hazard.setIndicationLevelId(indicationType.getIndicationItems().get(0).getId());
        } else {
            boolean flag = false;
            for (IndicationItems indication : indicationType.getIndicationItems()) {
                if (indication.getName().equalsIgnoreCase(indicationLevelName)) {
                    hazard.setIndicationLevelId(indication.getId());
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                hazard.setIndicationLevelId(indicationType.getIndicationItems().get(0).getId());
            }
        }
        String identificationType = getCellValue(row.getCell(6));
        hazard.setIdentificationType(identificationType);
        hazard.setName(sourceName);
        hazard.setHazardTypeId(hazardTypeItem.getId());
        hazard.setHazardTypeName(hazardTypeName);
        // 导入的code
        hazard.setCode(getCellValue(row.getCell(0)));
        return hazard;
    }

    private StandardRisk parseRisk(XSSFRow row, StaffBean user,String identificationType) {
        String accidentTypeName = getCellValue(row.getCell(7));
        DictData accidentTypeItem = dataService.matchDictData("事故类型", accidentTypeName);
        if (accidentTypeItem == null) {
            return null;
        }
        StandardRisk risk = new StandardRisk(user.getCode(), user.getName());
        risk.setRiskInfo(getCellValue(row.getCell(8)));
        risk.setRiskReason(getCellValue(row.getCell(9)));
        risk.setAccidentTypeId(accidentTypeItem.getId());
        if("LS".equals(identificationType)){
            //LS辨识方式
            risk.setPossibility((int) Double.parseDouble(getCellValue(row.getCell(10))));
            risk.setSeverity((int) Double.parseDouble(getCellValue(row.getCell(11))));
            risk.setRiskLevel(risk.getPossibility() * risk.getSeverity());
            RiskLevelDesc levelDesc = match(risk.getRiskLevel());
            risk.setControlLevel(levelDesc != null? levelDesc.getControlDesc() : "");
            risk.setPrecaution(getCellValue(row.getCell(14)));
            try {
                Integer residuePossibility = (int) Double.parseDouble(getCellValue(row.getCell(15)));
                Integer residueSeverity = (int) Double.parseDouble(getCellValue(row.getCell(16)));
                risk.setResiduePossibility(residuePossibility);
                risk.setResidueSeverity(residueSeverity);
                risk.setResidueLevel(residuePossibility * residueSeverity);
            } catch (NumberFormatException e) {
                logger.error(e.getMessage(),e);
            }
        }else{
            try {
                BigDecimal occurencePossibility=new BigDecimal(Double.parseDouble(getCellValue(row.getCell(19)))+"");
                BigDecimal frequently=new BigDecimal(Double.parseDouble(getCellValue(row.getCell(20)))+"");
                BigDecimal consequence=new BigDecimal(Double.parseDouble(getCellValue(row.getCell(21)))+"");
                risk.setOccurencePossibility(occurencePossibility);
                risk.setFrequently(frequently);
                risk.setConsequence(consequence);
            }catch (NumberFormatException e) {
                logger.error(e.getMessage(),e);
            }
        }

        return risk;
    }

    private RiskLevelDesc match(Integer riskLevel) {
        if (riskLevel != null) {
            for (Map.Entry<RiskLevelDesc, List<Integer>> entry : levelMap.entrySet()) {
                RiskLevelDesc key = entry.getKey();
                List<Integer> value = entry.getValue();
                if (value.contains(riskLevel)) {
                    return key;
                }
            }
        }
        return null;
    }

    private RiskLECDesc matchRiskLECDesc(BigDecimal riskLevel){
        if (riskLevel.compareTo(BigDecimal.ZERO)==1&&riskLevel.compareTo(new BigDecimal(20))==-1){
            return RiskLECDesc.LOW;
        }else if (riskLevel.compareTo(new BigDecimal(70))==-1){
            return RiskLECDesc.Minor;
        }else if (riskLevel.compareTo(new BigDecimal(160))==-1){
            return RiskLECDesc.Ordinary;
        }else if (riskLevel.compareTo(new BigDecimal(320))==-1){
            return RiskLECDesc.Serious;
        } else if (riskLevel.compareTo(new BigDecimal(320))==1){
            return RiskLECDesc.Important;
        }else{
            return null;
        }
    }

   /* @SuppressWarnings("unused")
	private void countRef(Map<String, DictData> configMap, String configId) {
        DictData config = configMap.get(configId);
        if (null == config) {
            config = dataService.queryOne(configId).getData();
            if (null == config.getReferenceCount()) {
                config.setReferenceCount(0L);
            }
            configMap.put(config.getId(), config);
        }
        config.setReferenceCount(config.getReferenceCount() + 1);
    }*/


    /**
     * 获取合并单元格的范围
     *
     * @param listCombineCell
     * @param cell
     * @return
     */
    private CellRangeAddress getCellRange(List<CellRangeAddress> listCombineCell, XSSFCell cell) {
        int firstC = 0, lastC = 0, firstR = 0, lastR = 0;
        for (CellRangeAddress ca : listCombineCell) {
            // 获得合并单元格的起始行, 结束行, 起始列, 结束列
            firstC = ca.getFirstColumn();
            lastC = ca.getLastColumn();
            firstR = ca.getFirstRow();
            lastR = ca.getLastRow();
            if (cell.getRowIndex() >= firstR && cell.getRowIndex() <= lastR) {
                if (cell.getColumnIndex() >= firstC && cell.getColumnIndex() <= lastC) {
                    return ca;
                }
            }
        }
        return null;
    }

    /**
     * 合并单元格处理,获取合并行
     *
     * @param sheet
     * @return List<CellRangeAddress>
     */
    public List<CellRangeAddress> getCombineCell(XSSFSheet sheet) {
        List<CellRangeAddress> list = new ArrayList<CellRangeAddress>();
        // 获得一个 sheet 中合并单元格的数量
        int sheetmergerCount = sheet.getNumMergedRegions();
        // 遍历所有的合并单元格
        for (int i = 0; i < sheetmergerCount; i++) {
            // 获得合并单元格保存进list中
            CellRangeAddress ca = sheet.getMergedRegion(i);
            list.add(ca);
        }
        return list;
    }

    /**
     * 获取单元格的值
     *
     * @param cell
     * @return
     */
    @SuppressWarnings("deprecation")
    public String getCellValue(XSSFCell cell) {
        if (cell == null)
            return "";
        if (cell.getCellTypeEnum() == CellType.STRING) {
            return cell.getStringCellValue();
        } else if (cell.getCellTypeEnum() == CellType.BOOLEAN) {
            return String.valueOf(cell.getBooleanCellValue());
        } else if (cell.getCellTypeEnum() == CellType.FORMULA) {
            return cell.getCellFormula();
        } else if (cell.getCellTypeEnum() == CellType.NUMERIC) {
            return String.valueOf(cell.getNumericCellValue());
        } else {
            return "";
        }
    }


    @Override
    public void reject(Audit audit, List<String> userIdList) {
        // TODO 流程驳回操作
    }

    @Override
    public void passApproval(Integer operation, Audit audit) {
        // TODO 流程提交成功操作
    }
}
